package run.halo.app.controller.admin.api;

import static org.springframework.data.domain.Sort.Direction.DESC;

import io.swagger.annotations.ApiOperation;
import java.util.List;
import javax.validation.Valid;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import run.halo.app.cache.AbstractStringCacheStore;
import run.halo.app.model.dto.SiteDetailDTO;
import run.halo.app.model.dto.SiteDTO;
import run.halo.app.model.dto.post.BasePostDetailDTO;
import run.halo.app.model.dto.post.BasePostMinimalDTO;
import run.halo.app.model.entity.Post;
import run.halo.app.model.entity.Site;
import run.halo.app.model.enums.SiteStatus;
import run.halo.app.model.params.PostContentParam;
import run.halo.app.model.params.SiteParam;
import run.halo.app.model.params.SiteQuery;
import run.halo.app.model.vo.SiteDetailVO;
import run.halo.app.model.vo.SiteListVO;
import run.halo.app.service.OptionService;
import run.halo.app.service.SiteService;
import run.halo.app.service.assembler.SiteAssembler;
import run.halo.app.utils.DateUtils;

/**
 * Site controller.
 *
 * @author meazty
 * @since 2022/7/30 16:23
 **/
@RestController
@RequestMapping("/api/admin/sites")
public class SiteController {

    private final SiteAssembler siteAssembler;

    private final SiteService siteService;

    private final AbstractStringCacheStore cacheStore;

    private final OptionService optionService;

    public SiteController(
        SiteAssembler siteAssembler,
        SiteService siteService,
        AbstractStringCacheStore cacheStore,
        OptionService optionService) {
        this.siteAssembler = siteAssembler;
        this.siteService = siteService;
        this.cacheStore = cacheStore;
        this.optionService = optionService;
    }

    @GetMapping
    @ApiOperation("Lists sites")
    public Page<? extends SiteDTO> pageBy(
        @PageableDefault(sort = {"priority", "createTime"}, direction = DESC) Pageable pageable,
        SiteQuery siteQuery,
        @RequestParam(value = "more", defaultValue = "true") Boolean more) {
        Page<Site> sitePage = siteService.pageBy(siteQuery, pageable);
        if (more) {
            return siteAssembler.convertToListVo(sitePage);
        }

        return siteAssembler.convertToDTO(sitePage);
    }

    @GetMapping("latest")
    @ApiOperation("Pages latest post")
    public List<SiteDTO> pageLatest(
        @RequestParam(name = "top", defaultValue = "10") int top) {
        return siteAssembler.convertToDTO(siteService.pageLatest(top).getContent());
    }

    @GetMapping("{siteId:\\d+}")
    @ApiOperation("Gets a site")
    public SiteDetailVO getBy(@PathVariable("siteId") Integer siteId) {
        Site site = siteService.getById(siteId);
        return siteAssembler.convertToDetailVo(site);
    }

    @PutMapping("{siteId:\\d+}/likes")
    @ApiOperation("Likes a site")
    public void likes(@PathVariable("siteId") Integer siteId) {
        siteService.increaseLike(siteId);
    }

    @PostMapping
    @ApiOperation("Creates a site")
    public SiteDetailVO createBy(@Valid @RequestBody SiteParam siteParam,
        @RequestParam(value = "autoSave", required = false, defaultValue = "false") Boolean autoSave
    ) {
        // Convert to
        Site site = siteParam.convertTo();
        return siteService.createBy(site, siteParam.getTagIds(), siteParam.getCategoryIds(),
            autoSave);
    }

    @PutMapping("{siteId:\\d+}")
    @ApiOperation("Updates a site")
    public SiteDetailVO updateBy(@Valid @RequestBody SiteParam siteParam,
        @PathVariable("siteId") Integer siteId,
        @RequestParam(value = "autoSave", required = false, defaultValue = "false") Boolean autoSave
    ) {
        // Get the site info
        Site siteToUpdate = siteService.getById(siteId);

        siteParam.update(siteToUpdate);
        return siteService.updateBy(siteToUpdate, siteParam.getTagIds(), siteParam.getCategoryIds(),
            autoSave);
    }

    @PutMapping("{siteId:\\d+}/status/{status}")
    @ApiOperation("Updates site status")
    public SiteDetailDTO updateStatusBy(
        @PathVariable("siteId") Integer siteId,
        @PathVariable("status") SiteStatus status) {
        Site site = siteService.updateStatus(status, siteId);

        return new SiteDetailDTO().convertFrom(site);
    }

    @PutMapping("status/{status}")
    @ApiOperation("Updates site status in batch")
    public List<Site> updateStatusInBatch(@PathVariable(name = "status") SiteStatus status,
        @RequestBody List<Integer> ids) {
        return siteService.updateStatusByIds(ids, status);
    }

    @DeleteMapping("{siteId:\\d+}")
    @ApiOperation("Deletes a site permanently")
    public void deletePermanently(@PathVariable("siteId") Integer siteId) {
        siteService.removeById(siteId);
    }

    @DeleteMapping
    @ApiOperation("Deletes sites permanently in batch by id array")
    public List<Site> deletePermanentlyInBatch(@RequestBody List<Integer> ids) {
        return siteService.removeByIds(ids);
    }

}
